﻿using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.Configuration;
using System;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Loader;

namespace Common.Framework.Core.Foundation
{
    public static class AssemblyLoadContextFoundation
    {
        /// <summary>
        /// 加载dll
        /// </summary>
        /// <param name="targetPath"></param>
        public static void Load(out string targetPath)
        {
            //匹配查找运行目录下的插件文件
            targetPath = ConfigurationPath.Combine(AppDomain.CurrentDomain.BaseDirectory);
            //运行入口程序
            string entryName = Assembly.GetEntryAssembly().GetName().Name;
            //获取执行文件同一目录下的其他dll
            var dlls = Directory.GetFiles(targetPath, "*.dll");
            foreach (var dll in dlls)
            {
                //排除主程序的dll
                if (entryName.Equals(Path.GetFileNameWithoutExtension(dll)))
                {
                    continue;
                }
                try
                {
                    //解决插件还引用其他主程序没有引用的第三方dll问题System.IO.FileNotFoundException
                    AssemblyLoadContext.Default.LoadFromAssemblyPath(dll);
                }
                catch (Exception)
                {
                    //非.net程序集类型的dll关联load时会报错，这里忽略就可以
                }
            }
        }

        /// <summary>
        /// 主模块这里需要把其他人员开发的插件注册进来
        /// </summary>
        /// <param name="partManager"></param>
        /// <param name="targetPath"></param>
        /// <returns></returns>
        public static ApplicationPartManager ConfigureApplicationPartManagerCustom(this ApplicationPartManager partManager, string targetPath)
        {
            // 主项目是asp.net core webapi 项目
            // 发布运行时，是用 Common.Framework.Main.Api 主项目运行

            // 插件项目也是asp.net core webapi 项目
            // 这样需要把插件注册进来，插件的路由是有插件项目单独指定。
            // 插件项目的命名做个约定，比如【Common.Framework.ModuleXXX.PlugXXX.Api】这样方便这里根据文件名注册
            var plugs = Directory.EnumerateFiles(targetPath, $"*.Module*.Plug*.dll").Select(AssemblyLoadContext.Default.LoadFromAssemblyPath);
            //加载插件 Assemlby 并注册到 MvcBuilder 中
            foreach (var item in plugs)
            {
                foreach (var part in new DefaultApplicationPartFactory().GetApplicationParts(item))
                {
                    partManager.ApplicationParts.Add(part);
                }
            }
            return partManager;
        }
    }
}
